﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Xml;
using EveAI.Live;
//using Math;
using EVEMap;

namespace eveDBToy1
{
    public partial class Form1 : Form
    {
        private eveMap m_mapSolarSystems;
        private eveMapDB m_MapDB;

        /// <summary>
        /// List of solar systems in the selected region, populated by the asset mapping operation
        /// </summary>
        List<eveSolarSystem> m_solarSystemsWithAssets = new List<eveSolarSystem>();

        public Form1()
        {
            InitializeComponent();
            m_mapSolarSystems = new eveMap();
            string ConnStr = System.Configuration.ConfigurationManager.ConnectionStrings["eveDBConnectionString"].ConnectionString;
            m_MapDB = new eveMapDB(ConnStr);
            lvRoute.View = View.Details;
            lvRoute.Columns.Add("Jumps");
            lvRoute.Columns.Add("System Name");
            lvRoute.Columns.Add("Assets Value");
            
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            m_MapDB.connect();
            m_MapDB.initSolarSystemGraph(m_mapSolarSystems);
            btnPlan.Enabled = true;
        }


        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //m_SQLConn.Close();
        }

        private void btnPlan_Click(object sender, EventArgs e)
        {
            if ((edtStart.Text.Length == 0) || (edtEnd.Text.Length == 0))
            {
                MessageBox.Show("Must specifiy valid start, end!");
                return;
            }
            int idStart = m_mapSolarSystems[edtStart.Text.ToUpper()].ID;
            int idEnd = m_mapSolarSystems[edtEnd.Text.ToUpper()].ID;
            List<int> route = m_mapSolarSystems.Djikstra(idStart, idEnd);
            lvRoute.Items.Clear();
            for (int i = 0; i < route.Count; i++)
            {
                string Name = m_mapSolarSystems[route[i]].Name;
                ListViewItem oItem = lvRoute.Items.Add(new ListViewItem(new String[] {Convert.ToString(i), Name}));
                //oItem.SubItems.Add(Name);
                //lbRoute.Items.Add(Name);
                //lbRoute
            }
        }

        private void btnGetAssets_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            Application.DoEvents();
            m_MapDB.loadAssets();
            Cursor.Current = Cursors.Default;
            Application.DoEvents();
        }

        private void btnMapAssets_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            Application.DoEvents();
            m_MapDB.AddAssetsToMap(m_mapSolarSystems, m_solarSystemsWithAssets);
            drawAssetsList();
            Cursor.Current = Cursors.Default;
            Application.DoEvents();
        }

        private void drawAssetsList()
        {
            double minConsolidate = Convert.ToDouble(edtConsolidationThreshold.Text);
            lvRoute.Items.Clear();
            foreach (eveSolarSystem solarSystem in m_solarSystemsWithAssets)
            {
                ListViewItem oItem = lvRoute.Items.Add(new ListViewItem(new String[] { 
                    Convert.ToString(solarSystem.Route.Count), solarSystem.Name, string.Format("{0,-14:c}", solarSystem.AssetsValue) }));
                if (solarSystem.needsConsolidation(minConsolidate))
                    oItem.Font = new Font(oItem.Font, oItem.Font.Style | FontStyle.Bold);
                if (solarSystem.Security < 0.5)
                    oItem.ForeColor = Color.OrangeRed;

            }
        }


        private void btnFindConfs_Click(object sender, EventArgs e)
        {

            /// key is a solarSystemID, value is a set of routeJunctions found for the key system's route to the hub
            Dictionary<int, List<routeJunction>> confluences = new Dictionary<int, List<routeJunction>>();
            foreach (eveSolarSystem solarSystem1 in m_solarSystemsWithAssets)
            {
                // todo - replace constant with parameter/tunable
                if (solarSystem1.AssetsValue < 5000000)
                    continue;
                List<int> route1 = new List<int>(solarSystem1.Route);
                route1.Reverse();
                List<routeJunction> solarSystem1Junctions = new List<routeJunction>();
                foreach (eveSolarSystem solarSystem2 in m_solarSystemsWithAssets)
                {
                    if (solarSystem1 == solarSystem2)
                        continue;
                    // todo - replace constant with parameter/tunable
                    if (solarSystem2.AssetsValue < 5000000)
                        continue;
                    // compare the 2 routes working backward from the hub: the last value where they are equal is where they join.
                    List<int> route2 = new List<int>(solarSystem2.Route);
                    route2.Reverse();
                    int i = 0;
                    int maxIndex = Math.Min(route1.Count, route2.Count);
                    while (i < maxIndex && (route1[i] == route2[i]))
                        ++i;
                    --i;
                    if (i == 0)
                        continue; // the two routes only join at the hub;
                    routeJunction junction = new routeJunction();
                    junction.solarSystem1 = solarSystem1.ID;
                    junction.solarSystem2 = solarSystem2.ID;
                    junction.junctureSytem = route1[i];
                    junction.hubDistance = i;
                    List<int> dummy = m_mapSolarSystems.Djikstra(solarSystem2.ID, route1[i]);
                    junction.junctionDistance = dummy.Count - 1;
                    // todo - replace constant with parameter/tunable
                    if (junction.junctionDistance < 5)
                        solarSystem1Junctions.Add(junction);
                }
                // sort the list of junctions by distance of junction from hub, farthest away first
                solarSystem1Junctions.Sort((x, y) => y.hubDistance.CompareTo(x.hubDistance));
                confluences.Add(solarSystem1.ID, solarSystem1Junctions);
            }
            // get a list of systems, most valuable first
            List<eveSolarSystem> systemByValue = new List<eveSolarSystem>(m_solarSystemsWithAssets);
            systemByValue.Sort((x, y) => y.AssetsValue.CompareTo(x.AssetsValue));
            string report = "";
            Form2 fm = new Form2();
            int valIndex = 0;
            while (valIndex < systemByValue.Count)
            {
                eveSolarSystem currentSystem = systemByValue[valIndex++];
                if (currentSystem.Security < 0.5)
                    continue;

                if (currentSystem.Route.Count == 0)
                    continue;
                List<routeJunction> confluentRoutes;
                if (!confluences.TryGetValue(currentSystem.ID, out confluentRoutes))
                    continue;
                //List<routeJunction> confluentRoutes = confluences[currentSystem.ID];
                report += string.Format("{0} value {1:c} {2} jumps\n", currentSystem.Name, 
                    currentSystem.AssetsValue, currentSystem.Route.Count);
                for (int j = 0; j < confluentRoutes.Count; j++)
                {
                    eveSolarSystem joiningSystem = m_mapSolarSystems[confluentRoutes[j].solarSystem2];
                    eveSolarSystem intersectionSystem = m_mapSolarSystems[confluentRoutes[j].junctureSytem];
                    report += string.Format("\t{0} value {1:c} joins at {2}, {3} jumps\n", joiningSystem.Name, joiningSystem.AssetsValue,
                        intersectionSystem.Name, confluentRoutes[j].junctionDistance);
                }
            }
            fm.ReportText = report;
            fm.ShowDialog();

        }

        private void edtConsolidationThreshold_TextChanged(object sender, EventArgs e)
        {
            drawAssetsList();
        }


        private void btnCoalesce_Click(object sender, EventArgs e)
        {
            // only works if m_mapSolarSystems has already had the "add assets to map" operation done on it.
            eveMap tmpMap = new eveMap(m_mapSolarSystems);
            List<eveSolarSystem> tmpRegionList = new List<eveSolarSystem>();
            foreach (eveSolarSystem sys in m_solarSystemsWithAssets)
            {
                // doing this instead of a copy ctor call, to get the systems out of the map copy
                eveSolarSystem tmp = tmpMap[sys.ID];
                tmpRegionList.Add(tmp);
            }
            List<coalesceAssetsList> coalesce = tmpMap.coalesceAssets(tmpRegionList);
            string coalesceRoutes = "";
            //Form3 courierPlan = new Form3();
            foreach (coalesceAssetsList assetsTmp in coalesce)
            {
                coalesceRoutes += assetsTmp.ToString() + "\n";
                //ListViewItem oItem = courierPlan.lvCourier.Items.Add(new ListViewItem(new String[] { 
                //    assetsTmp.StartName, assetsTmp.EndName, string.Format("{0,-14:c}", assetsTmp.Collateral), Convert.ToString(assetsTmp.Jumps) }));

            }
            //courierPlan.ShowDialog();
            Form2 coalesceReport = new Form2();
            coalesceReport.ReportText = coalesceRoutes;
            coalesceReport.ShowDialog();

        }

        private void btnConsolidateAssets_Click(object sender, EventArgs e)
        {
            double minConsolidate = Properties.Settings.Default.minConsolidateAssetValue;
            List<eveSolarSystem> combineSystems = m_solarSystemsWithAssets.Where(x => x.needsConsolidation(minConsolidate)).ToList();
            Form2 consolidateReport = new Form2();
        }
    }

}
